package com.server.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.server.pojo.ResponseBean;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * @ClassName: RestAuthorizationEntryPoint
 * @Description: 当未登录或者token失效的时候，访问接口时，自定义的返回结果
 *               当用户未登录或登录状态失效（比如 token 过期、无效）时，访问需要认证的接口，会返回你自定义的 JSON 响应（而不是 Spring Security 默认的登录页面或错误信息）。
 * @Author: SongHL
 * @Date: 2025/9/14
 */
//AuthenticationEntryPoint 是 Spring Security 提供的接口，
//专门用于处理 “未认证” 场景（用户未登录或认证失败）。
//实现这个接口并重写 commence 方法，就能自定义未认证时的处理逻辑。
@Component
public class RestAuthorizationEntryPoint implements AuthenticationEntryPoint {

    //当用户未认证访问受保护资源时，Spring Security 会自动调用这个方法。
    //参数说明：
    //request：当前请求对象
    //response：响应对象（用于返回自定义信息）
    //authException：认证失败的异常（包含失败原因，比如 token 无效、过期等）
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        //1.设置响应编码格式为UTF-8
        response.setCharacterEncoding("UTF-8");
        //2.响应内容格式为json
        response.setContentType("application/json");
        //3. 获取响应输出流（用于写入 JSON 数据）(PrintWriter 是用于向响应体中写入数据的工具。)
        PrintWriter writer = response.getWriter();
        //4. 构建自定义的错误响应对象
        ResponseBean bean = ResponseBean.error("未登录，请重新登录!");
        bean.setCode(401); // 401 是 HTTP 标准状态码，表示“未授权”
        //5. 将 ResponseBean 转换为 JSON 字符串并写入响应
        //ObjectMapper：
        //  是 Jackson 库的核心类，负责 Java 对象和 JSON 之间的相互转换（序列化和反序列化）。
        //  序列化：将 Java 对象 → JSON 字符串（如你代码中的操作）。
        //  反序列化：将 JSON 字符串 → Java 对象（例如接收前端 JSON 数据时使用）。
        //writeValueAsString(bean)：
        //  是 ObjectMapper 的方法，作用是将传入的 Java 对象（这里的 bean 是 ResponseBean 实例）转换为 JSON 格式的字符串。
        writer.write(new ObjectMapper().writeValueAsString(bean));
        // 6. 刷新输出流，确保数据发送到前端
        writer.flush();
        writer.close();
    }
}
